﻿using System;
using System.Data;
using System.Xml;
using SdmxMl.Common;
using SdmxMl.Structure;
using SdmxMl.Manager;
using SdmxMl.SmsImportCfg;

namespace GeoPlugIn
{
    /// <summary>
    /// Class for generation of SDMX Concepts for State & Territories source document description
    /// </summary>
    /// <remarks>Used only once, updated with MetaStat editor afterwards</remarks>
    public class SdmxSpec
    {
        #region Internal Members

        private DataTable table;
        private WorkSheetHelper wsh;
        private const int colId = 4;
        private const int colName = 3;
        private const int colSpec = 5;
        private const int col_eCH = 6;
        private const int colDescr = 7;

        private int rowGerman;
        private int rowFrench;

        #endregion

        #region Constructor

        /// <summary>C'tor</summary>
        /// <param name="ir">Source document reader interface</param>
        public SdmxSpec(IReader ir)
        {
            ExcelSTreader reader = ir as ExcelSTreader;
            if (reader == null)
                throw new ApplicationException("Invalid reader received for States and Territories.");

            table = reader.Spreadsheet.WorkbookData.Tables["ReadMe"];
            wsh = new WorkSheetHelper(table);
        }

        #endregion

        #region SDMX ConceptScheme generation

        public void Convert(string folder)
        {
            DetectlangRows();

            ConceptSchemeType cst = new ConceptSchemeType();
            cst.AgencyId = "CH1_RN";
            cst.Id = "CS_SPEC_COUNTRIESGEO";
            cst.Name.UpdateForLanguage("de",
                wsh.GetCellContent(rowGerman - 5, 1) + " - " + wsh.GetCellContent(rowGerman - 3, 1));

            cst.Name.UpdateForLanguage("fr",
                wsh.GetCellContent(rowFrench - 5, 1) + " - " + wsh.GetCellContent(rowFrench - 3, 1));

            string key = string.Empty;
            while ((key = wsh.GetCellContent(rowGerman, colId)) != string.Empty)
            {
                ConceptType concept = new ConceptType();
                concept.Id = key;
                concept.Name.UpdateForLanguage("de", wsh.GetCellContent(rowGerman, colName));
                concept.Name.UpdateForLanguage("fr", wsh.GetCellContent(rowFrench, colName));

                concept.Description.UpdateForLanguage("de", wsh.GetCellContent(rowGerman, colDescr));
                concept.Description.UpdateForLanguage("fr", wsh.GetCellContent(rowFrench, colDescr));

                Annotation ann = new Annotation("eCH-0072");
                ann.Title = "Tag";
                ann.Text.UpdateDefaultText(wsh.GetCellContent(rowGerman, col_eCH));
                concept.AnnotationList.Add(ann);

                SetTextFormat(concept, wsh.GetCellContent(rowGerman, colSpec));

                cst.ConceptList.Add(concept);
                ++rowFrench;
                ++rowGerman;
            }


            SmManager sm = new SmManager();
            sm.PutArtefact(SdmxArtefactType.Concepts, cst);
            XmlDocument xDoc = sm.GetAsDocument();
            xDoc.Save(folder + "\\" + cst.FullIdent + ".xml");

        }
        #endregion

        #region Internal Methods helpers

        /// <summary> Generate text format and USAGE annotation </summary>
        /// <param name="concept">concept currently in creation</param>
        /// <param name="formatInfo">packed format source cell content</param>
        private void SetTextFormat(ConceptType concept, string formatInfo)
        {
            // Annotation USAGE: Facultatif / obligatoire
            string[] arrFak = { "Optional", "fakultativ", "Facultatif", "facoltativo" };
            string[] arrMand = { "Mandatory", "obligatorisch", "Obligatoire", "obbligatorio" };

            if (formatInfo.IndexOf("- fak.") > 0)
            {
                Annotation ann = new Annotation("USAGE");
                int i = 0;
                foreach (string lg in LangSupport.SupportedLanguages)
                    ann.Text.UpdateForLanguage(lg, arrFak[i++]);
                concept.AnnotationList.Add(ann);
            }

            else if (formatInfo.IndexOf("- obl.") > 0)
            {
                Annotation ann = new Annotation("USAGE");
                int i = 0;
                foreach (string lg in LangSupport.SupportedLanguages)
                    ann.Text.UpdateForLanguage(lg, arrMand[i++]);
                concept.AnnotationList.Add(ann);
            }

            // Text Format
            int ndx = 0;
            if ((ndx = formatInfo.IndexOf("/a")) > 0)
            {
                concept.TextFormat.TextType = TextTypeType.String;
                string size = formatInfo.Substring(0, ndx);
                concept.TextFormat.maxLength = size;
            }
            else if (formatInfo.StartsWith("j/n"))
            {
                concept.TextFormat.TextType = TextTypeType.Boolean;
            }

            else if ((ndx = formatInfo.IndexOf("/n")) > 0)
            {
                concept.TextFormat.TextType = TextTypeType.Integer;
                string size = formatInfo.Substring(0, ndx);
                concept.TextFormat.maxLength = size;
            }

        }

        /// <summary>Locates index of next empty source row </summary>
        /// <param name="rowStart">current row to start with</param>
        /// <returns>value for next empty row</returns>
        private int GotoNextEmpty(int rowStart)
        {
            while (rowStart <= table.Rows.Count && wsh.GetCellContent(rowStart, colId).Length > 0)
                ++rowStart;
            if (rowStart >= table.Rows.Count)
                throw new ApplicationException("Unexpected end of file encountred!");

            return rowStart;
        }

        /// <summary>/  Deetects first row for one language bloc info </summary>
        /// <param name="rowStart">index of row to work with</param>
        /// <returns></returns>
        private int DetectOnelangRows(int rowStart)
        {
            int rowDetect = -1;
            for (int row = rowStart; row <= table.Rows.Count; ++row)
            {
                if (wsh.GetCellContent(row, colId).Length > 0)
                {
                    rowDetect = row + 1; // skip title row
                    break;
                }
            }

            return rowDetect;
        }

        /// <summary>
        /// Detects start rows for German and French blocs
        /// </summary>
        private void DetectlangRows()
        {
            rowGerman = rowFrench = -1;
            rowGerman = DetectOnelangRows(1);
            if (rowGerman > 0)
            {
                rowFrench = DetectOnelangRows(GotoNextEmpty(rowGerman));
            }

            if (rowGerman == -1 || rowFrench == -1)
                throw new ApplicationException("Unexpected: language not found!");

        }

        #endregion
    }

}
